﻿using System;
using System.Collections.Generic;
using System.Reflection;

namespace Vbyte.SharpOrm.Util
{
    /// <summary>
    /// 动态(可停靠)类型实现
    /// </summary>
    public class DockType
    {
        /// <summary>
        /// 从当前实例类型初始话一个动态类型
        /// </summary>
        /// <param name="originalInstance">原始实例</param>
        public DockType(object originalInstance)
        {
            if (originalInstance == null)
                throw new ArgumentNullException("originalInstance");

            currentInstance = originalInstance;
            originalType = originalInstance.GetType();
            _currentType = originalType;
        }

        private Type originalType; 
        /// <summary>
        /// 获取原始类型
        /// </summary>
        public Type OriginalType
        {
            get { return originalType; }
        }

        private object currentInstance = null;
        /// <summary>
        /// 获取运行时的当前实例
        /// </summary>
        public object CurrentInstance
        {
            get { return currentInstance; }
        }

        public Type _currentType;
        /// <summary>
        /// 获取实体的当前类型
        /// </summary>
        public Type CurrentType
        {
            get { return _currentType; }
        }

        /// <summary>
        /// 演变成目标类型
        /// </summary>
        /// <typeparam name="T">目标类型</typeparam>
        public T EvolveTo<T>()
        {
            if (_currentType.Equals(typeof(T)))
            {
                return (T)currentInstance;
            }
            else
            {
                Type targetType = typeof(T);
                bool canTrans = false;
                bool targetNeddConvert = false;

                if (targetType.IsInterface)
                {
                   canTrans =  (_currentType.GetInterface(targetType.FullName) != null);
                }
                else if (targetType.IsClass)
                {
                    canTrans = _currentType.IsSubclassOf(targetType);
                }
                else
                {
                    if (_currentType.GetInterface(typeof(IConvertible).FullName) != null)
                    {
                        canTrans = true;
                        targetNeddConvert = true;
                    }
                }

                if (!canTrans)
                {
                    throw new InvalidCastException("演变为目标类型失败：" + targetType.AssemblyQualifiedName);
                }
                else
                {
                    T result = (targetNeddConvert) ? (T)Convert.ChangeType(currentInstance, targetType) : (T)currentInstance;
                    currentInstance = result;
                    _currentType = targetType;
                    return result;
                }
            }
        }

        /// <summary>
        /// 尝试以目标类型(当前类型兼容于目标类型)运行制定方法
        /// </summary>
        /// <typeparam name="T">目标类型</typeparam>
        /// <param name="instance">来源实例</param>
        /// <param name="runMethod">目标类型的方法</param>
        /// <param name="parameters">
        /// 调用的方法或构造函数的参数列表。这是一个对象数组，这些对象与要调用的方法或构造函数的参数具有相同的数量、顺序和类型。
        /// 如果没有任何参数，则 parameters应为 null。 如果此实例所表示的方法或构造函数采用 ref 参数（在 Visual Basic 中为 ByRef），
        /// 使用此函数调用该方法或构造函数时，该参数不需要任何特殊属性。如果数组中的对象未用值来显式初始化，则该对象将包含该对象类型的默认值。
        /// 对于引用类型的元素，该值为null。对于值类型的元素，该值为 0、0.0 或 false，具体取决于特定的元素类型。</param>
        /// <returns>以目标类型的方式运行是否成功</returns>
        public static bool TryDoAs<T>(object instance, MethodInfo runMethod, object[] parameters)
        {
            DockType Dock = new DockType(instance);
            bool result = true;
            try
            {
                T target = Dock.EvolveTo<T>();
                runMethod.Invoke(target, parameters);
            }
            catch (Exception) 
            {
                result = false;
            }
            return result;
        }

    }
}
